package com.zhx.common.common.service.frequencycontrol;


import com.zhx.common.common.domain.dto.FrequencyControlDTO;
import com.zhx.common.common.util.AssertUtil;
import org.apache.commons.lang3.ObjectUtils;

import java.util.List;

/**
 * 限流工具类 提供编程式的限流调用方法
 *
 * @author linzhihan
 * @date 2023/07/03
 */
public class FrequencyControlUtil {

    /**
     * 单限流策略的调用方法-编程式调用
     *
     * @param strategyName     策略名称
     * @param frequencyControl 单个频控对象
     * @param supplier         服务提供着
     * @return 业务方法执行结果
     * @throws Throwable
     */
    public static <T, K extends FrequencyControlDTO> T executeWithFrequencyControl(String strategyName, K frequencyControl, AbstractFrequencyControlService.SupplierThrowWithoutParam<T> supplier) throws Throwable {
        AbstractFrequencyControlService<K> frequencyController = FrequencyControlStrategyFactory.getFrequencyControllerByName(strategyName);
        return frequencyController.executeWithFrequencyControl(frequencyControl, supplier);
    }

    public static <K extends FrequencyControlDTO> void executeWithFrequencyControl(String strategyName, K frequencyControl, AbstractFrequencyControlService.Executor executor) throws Throwable {
        AbstractFrequencyControlService<K> frequencyController = FrequencyControlStrategyFactory.getFrequencyControllerByName(strategyName);
        frequencyController.executeWithFrequencyControl(frequencyControl, () -> {
            executor.execute();
            return null;
        });
    }


    /**
     * 使用多限流策略进行编程式调用的方法。
     *
     * @param strategyName 策略名称，用于选择具体的限流策略。
     * @param frequencyControlList 频率控制列表，包含了需要进行频率控制的方法的定义及其执行顺序。
     * @param supplier 函数式接口，代表了每个频率控制方法所执行的不同业务逻辑。
     * @return 执行业务方法后的返回值。
     * @throws Throwable 如果被限流或者限流策略定义错误，则会抛出异常。
     */
    public static <T, K extends FrequencyControlDTO> T executeWithFrequencyControlList(String strategyName, List<K> frequencyControlList, AbstractFrequencyControlService.SupplierThrowWithoutParam<T> supplier) throws Throwable {
        // 检查频控列表中是否存在Key为空的项
        boolean existsFrequencyControlHasNullKey = frequencyControlList.stream().anyMatch(frequencyControl -> ObjectUtils.isEmpty(frequencyControl.getKey()));
        AssertUtil.isFalse(existsFrequencyControlHasNullKey, "限流策略的Key字段不允许出现空值");

        // 根据策略名称获取对应的频率控制服务
        AbstractFrequencyControlService<K> frequencyController = FrequencyControlStrategyFactory.getFrequencyControllerByName(strategyName);

        // 执行频率控制列表中的所有方法，并返回结果
        return frequencyController.executeWithFrequencyControlList(frequencyControlList, supplier);
    }


    /**
     * 构造器私有
     */
    private FrequencyControlUtil() {

    }

}
